/*
 * Copyright 1999,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.sf.webdav.methods;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.webdav.IMimeTyper;
import net.sf.webdav.ITransaction;
import net.sf.webdav.IWebdavStore;
import net.sf.webdav.StoredObject;
import net.sf.webdav.WebdavStatus;
import net.sf.webdav.locking.ResourceLocks;
import x.org.apache.http.entity.ContentProducer;

public class DoGet extends DoHead {

    private static org.slf4j.Logger LOG = org.slf4j.LoggerFactory
            .getLogger(DoGet.class);

    public DoGet(IWebdavStore store, String dftIndexFile, String insteadOf404,
            ResourceLocks resourceLocks, IMimeTyper mimeTyper,
            int contentLengthHeader) {
        super(store, dftIndexFile, insteadOf404, resourceLocks, mimeTyper,
                contentLengthHeader);

    }

    @Override
    protected void doBody(final ITransaction transaction, final HttpServletResponse resp,
           final String path) {

        try {
            StoredObject so = _store.getStoredObject(transaction, path);
            if (so.isNullResource()) {
                String methodsAllowed = DeterminableMethod
                        .determineMethodsAllowed(so);
                resp.addHeader("Allow", methodsAllowed);
                resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
                return;
            }
            //OutputStream out = resp.getOutputStream();
            ContentProducer content = new ContentProducer() {
				
				public void writeTo(OutputStream out) throws IOException {
		            InputStream in = _store.getResourceContent(transaction, path);
		            try {
		                int read = -1;
		                byte[] copyBuffer = new byte[BUF_SIZE];

		                while ((read = in.read(copyBuffer, 0, copyBuffer.length)) != -1) {
		                    out.write(copyBuffer, 0, read);
		                }
		            } finally {
		                // flushing causes a IOE if a file is opened on the webserver
		                // client disconnected before server finished sending response
		                try {
		                    in.close();
		                } catch (Exception e) {
		                    LOG.warn("Closing InputStream causes Exception!\n"
		                            + e.toString());
		                }
//		                try {
//		                    out.flush();
//		                    out.close();
//		                } catch (Exception e) {
//		                    LOG.warn("Flushing OutputStream causes Exception!\n"
//		                            + e.toString());
//		                }
		            }
				}
            	
            };
            
            sendContent(resp, content);
            
        } catch (Exception e) {
            LOG.trace(e.toString());
        }
    }

    @Override
    protected void folderBody(final ITransaction transaction, final String path,
           final HttpServletResponse resp, final HttpServletRequest req)
            throws IOException {

        StoredObject so = _store.getStoredObject(transaction, path);
        if (so == null) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND, req
                    .getRequestURI());
        } else {

            if (so.isNullResource()) {
                String methodsAllowed = DeterminableMethod
                        .determineMethodsAllowed(so);
                resp.addHeader("Allow", methodsAllowed);
                resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
                return;
            }

            if (so.isFolder()) {
                // TODO some folder response (for browsers, DAV tools
                // use propfind) in html?
            	
                final DateFormat shortDF= getDateTimeFormat(req.getLocale());
                resp.setContentType("text/html");
                resp.setCharacterEncoding("UTF8");
                
            	ContentProducer content = new ContentProducer() {
					public void writeTo(OutputStream out)
							throws IOException {
		                String[] children = _store.getChildrenNames(transaction, path);
		                children = children == null ? new String[] {} : children;
		                StringBuilder childrenTemp = new StringBuilder();
		                childrenTemp.append("<html><head><title>Content of folder");
		                childrenTemp.append(path);
		                childrenTemp.append("</title><style type=\"text/css\">");
		                childrenTemp.append(getCSS());
		                childrenTemp.append("</style></head>");
		                childrenTemp.append("<body>");
		                childrenTemp.append(getHeader(transaction, path, resp, req));
		                childrenTemp.append("<table>");
		                childrenTemp.append("<tr><th>Name</th><th>Size</th><th>Created</th><th>Modified</th></tr>");
		                childrenTemp.append("<tr>");
		                childrenTemp.append("<td colspan=\"4\"><a href=\"../\">Parent</a></td></tr>");
		                boolean isEven= false;
		                for (String child : children) {
		                    isEven= !isEven;
		                    childrenTemp.append("<tr class=\"");
		                    childrenTemp.append(isEven ? "even" : "odd");
		                    childrenTemp.append("\">");
		                    childrenTemp.append("<td>");
		                    childrenTemp.append("<a href=\"");
		                    childrenTemp.append(child);
		                    StoredObject obj= _store.getStoredObject(transaction, path+"/"+child);
		                    if (obj.isFolder())
		                    {
		                        childrenTemp.append("/");
		                    }
		                    childrenTemp.append("\">");
		                    childrenTemp.append(child);
		                    childrenTemp.append("</a></td>");
		                    if (obj.isFolder())
		                    {
		                        childrenTemp.append("<td>Folder</td>");
		                    }
		                    else
		                    {
		                        childrenTemp.append("<td>");
		                        childrenTemp.append(obj.getResourceLength());
		                        childrenTemp.append(" Bytes</td>");
		                    }
		                    if (obj.getCreationDate() != null)
		                    {
		                        childrenTemp.append("<td>");
		                        childrenTemp.append(shortDF.format(obj.getCreationDate()));
		                        childrenTemp.append("</td>");
		                    }
		                    else
		                    {
		                        childrenTemp.append("<td></td>");
		                    }
		                    if (obj.getLastModified() != null)
		                    {
		                        childrenTemp.append("<td>");
		                        childrenTemp.append(shortDF.format(obj.getLastModified()));
		                        childrenTemp.append("</td>");
		                    }
		                    else
		                    {
		                        childrenTemp.append("<td></td>");
		                    }
		                    childrenTemp.append("</tr>");
		                }
		                childrenTemp.append("</table>");
		                childrenTemp.append(getFooter(transaction, path, resp, req));
		                childrenTemp.append("</body></html>");
		                out.write(childrenTemp.toString().getBytes("UTF-8"));
					}
            		
            	};

                //OutputStream out = resp.getOutputStream();
            	sendContent(resp, content);
            }
        }
    }

    /**
     * Return the CSS styles used to display the HTML representation
     * of the webdav content.
     * 
     * @return String returning the CSS style sheet used to display result in html format
     */
    protected String getCSS()
    {
        // The default styles to use
       String retVal= "body {\n"+
                "	font-family: Arial, Helvetica, sans-serif;\n"+
                "}\n"+
                "h1 {\n"+
                "	font-size: 1.5em;\n"+
                "}\n"+
                "th {\n"+
                "	background-color: #9DACBF;\n"+
                "}\n"+
                "table {\n"+
                "	border-top-style: solid;\n"+
                "	border-right-style: solid;\n"+
                "	border-bottom-style: solid;\n"+
                "	border-left-style: solid;\n"+
                "}\n"+
                "td {\n"+
                "	margin: 0px;\n"+
                "	padding-top: 2px;\n"+
                "	padding-right: 5px;\n"+
                "	padding-bottom: 2px;\n"+
                "	padding-left: 5px;\n"+
                "}\n"+
                "tr.even {\n"+
                "	background-color: #CCCCCC;\n"+
                "}\n"+
                "tr.odd {\n"+
                "	background-color: #FFFFFF;\n"+
                "}\n"+
                "";
        try
        {
            // Try loading one via class loader and use that one instead
            ClassLoader cl = getClass().getClassLoader();
            InputStream iStream = cl.getResourceAsStream("webdav.css");
            if(iStream != null)
            {
                // Found css via class loader, use that one
                StringBuilder out = new StringBuilder();
                byte[] b = new byte[4096];
                for (int n; (n = iStream.read(b)) != -1;)
                {
                    out.append(new String(b, 0, n));
                }
                retVal= out.toString();
            }
        }
        catch (Exception ex)
        {
            LOG.error("Error in reading webdav.css", ex);
        }

        return retVal;
    }

    /**
     * Return this as the Date/Time format for displaying Creation + Modification dates
     * 
     * @param browserLocale
     * @return DateFormat used to display creation and modification dates
     */
    protected DateFormat getDateTimeFormat(Locale browserLocale)
    {
        return SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.MEDIUM, browserLocale);
    }

    /**
     * Return the header to be displayed in front of the folder content
     * 
     * @param transaction
     * @param path
     * @param resp
     * @param req
     * @return String representing the header to be display in front of the folder content
     */
    protected String getHeader(ITransaction transaction, String path,
            HttpServletResponse resp, HttpServletRequest req)
    {
        return "<h1>Content of folder "+path+"</h1>";
    }

    /**
     * Return the footer to be displayed after the folder content
     * 
     * @param transaction
     * @param path
     * @param resp
     * @param req
     * @return String representing the footer to be displayed after the folder content
     */
    protected String getFooter(ITransaction transaction, String path,
            HttpServletResponse resp, HttpServletRequest req)
    {
        return "";
    }
}
